package fieldmaps.database;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;

import org.apache.log4j.Logger;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Polygon;

import fieldmaps.types.VoronoiMapInfo;

public class DatabaseVoronoiMap extends DatabaseGenericMap {
	private static Logger LOGGER = Logger.getLogger(DatabaseVoronoiMap.class);

	private VoronoiMapInfo mapHeader;

	public DatabaseVoronoiMap() {
		this.mapHeader = new VoronoiMapInfo();
	}

	public VoronoiMapInfo getVoronoiInfo() {
		return this.mapHeader;
	}

	/**
	 * 
	 * 
	 * @param mapName
	 * @param voronoiInfo
	 * @return
	 * @throws IllegalArgumentException
	 */
	public static DatabaseVoronoiMap createMap(String mapName, VoronoiMapInfo voronoiInfo) throws IllegalArgumentException {
		if (voronoiInfo == null || mapName == null || mapName.isEmpty()) {
			throw new IllegalArgumentException();
		}
		if (DatabaseConnection.getConnectionInstance() == null) {
			throw new IllegalAccessError("DataBase connection is down!");
		}

		DatabaseVoronoiMap dbMap = new DatabaseVoronoiMap();

		try {
			PreparedStatement statement;
			
			statement = DatabaseConnection.getConnectionInstance().prepareStatement(
					"INSERT INTO map_table (MAP_NAME, MAP_TYPE) VALUES (?,?)");
			
			statement.setString(1, mapName);
			statement.setString(2, "VORONOI");
			statement.execute();
			
			dbMap.loadMapId(mapName);

			statement = DatabaseConnection.getConnectionInstance().prepareStatement(
					"INSERT INTO voronoi_map_info (MAP_ID, ULXMAP, ULYMAP, BRXMAP, BRYMAP) VALUES (?,?,?,?,?)");

			statement.setInt(1, dbMap.getMapId());
			statement.setDouble(2, voronoiInfo.getxUpperLeft());
			statement.setDouble(3, voronoiInfo.getyUpperLeft());
			statement.setDouble(4, voronoiInfo.getxLowerRight());
			statement.setDouble(5, voronoiInfo.getyLowerRight());
			statement.execute();

			dbMap.loadHeader();
			
			return dbMap;
		} catch (SQLException e) {
			LOGGER.error("SQL Query error!: " + e.getMessage());
			e.printStackTrace();
		}
		return null;
	}

	private void loadHeader() throws SQLException {

		PreparedStatement statement = DatabaseConnection.getConnectionInstance().prepareStatement(
					"SELECT ULXMAP, ULYMAP, BRXMAP, BRYMAP FROM voronoi_map_info WHERE map_id = ?");
		statement.setInt(1, getMapId());
		ResultSet rs = statement.executeQuery();

		if (rs.next()) {
			this.mapHeader.setxLowerRight(rs.getDouble("BRXMAP"));
			this.mapHeader.setyLowerRight(rs.getDouble("BRYMAP"));
			this.mapHeader.setxUpperLeft(rs.getDouble("ULXMAP"));
			this.mapHeader.setyUpperLeft(rs.getDouble("ULYMAP"));
		}
	}

	public static DatabaseVoronoiMap loadMap(String name) {
		if (name == null || name.isEmpty()) {
			throw new IllegalArgumentException();
		}
		if (DatabaseConnection.getConnectionInstance() == null) {
			throw new IllegalAccessError("DataBase connection is down!");
		}
		
		DatabaseVoronoiMap dbMap = new DatabaseVoronoiMap();
		
		try {
			dbMap.loadMapId(name);
			dbMap.loadHeader();
			
			return dbMap;

		} catch (SQLException e) {
			LOGGER.error(e.getMessage());
		}
		
		return null;
	}

	public VoronoiMapInfo getMapInfo() {
		return mapHeader;
	}

	@Override
	public Coordinate[] getBorderCoordinates() {
		Coordinate[] coordinates = new Coordinate[2];
		coordinates[0] = new Coordinate(mapHeader.getxUpperLeft(), mapHeader.getyUpperLeft());
		coordinates[1] = new Coordinate(mapHeader.getxLowerRight(), mapHeader.getyLowerRight());
		return coordinates;
	}

	@Override
	public Map<Object, Double> getWeightedNeighborsArea(Polygon polygon)
			throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

//	@Override
//	public GenericMap binaryOperation(GenericMap otherMap, ICallbackBinary callback) throws MapAlgebraException {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public GenericMap unaryOperation(ICallbackUnary callback) throws MapAlgebraException {
//		Polygon polygon;
//		GenericMap newMap = DatabaseVoronoiMap.createMap(callback.newMapName(), this.mapHeader);
//		
//		startCellIteration();
//		try {
//			while ((polygon = getNextCell()) != null) {
//				Integer userData = (Integer) callback.doOperation(polygon.getUserData());
//				newMap.addCell(polygon.getCoordinates(), userData);
//			}
//		} catch (NoSuchElementException e) {
//			LOGGER.info("New map: " + callback.newMapName() + " successfully created!");
//			return newMap;
//		} catch (SQLException e) {
//			LOGGER.error(e.getMessage());
//		}
//		resetCellIteration();
//		return null;
//	}
}
